package binder

type SymbolTable struct {
	Table map[string][]*Symbol
}

func NewSymbolTable() *SymbolTable {
	return &SymbolTable{Table: make(map[string][]*Symbol)}
}

func NewSymbolTableWithSymbols(symbols []*Symbol) *SymbolTable {
	var result = &SymbolTable{Table: make(map[string][]*Symbol)}
	for _, symbol := range symbols {
		result.Table[symbol.Name] = append(result.Table[symbol.Name], symbol)
	}
	return result
}

func (s *SymbolTable) HasSymbol(name string, meanings ...SymbolFlags) bool {
	return s.GetSymbol(name, meanings...) != nil
}

func (s *SymbolTable) GetSymbols(meanings ...SymbolFlags) []*Symbol {
	var result []*Symbol
	for name, _ := range s.Table {
		result = append(result, s.GetSymbolsOfName(name, meanings...)...)
	}
	return result
}

func (s *SymbolTable) GetSymbolsOfName(name string, meanings ...SymbolFlags) []*Symbol {
	var result []*Symbol
outer:
	for _, symbol := range s.Table[name] {
		for _, meaning := range meanings {
			if symbol.Flags&meaning == 0 {
				continue outer
			}
		}
		result = append(result, symbol)
	}
	return result
}

func (s *SymbolTable) GetSymbol(name string, meanings ...SymbolFlags) *Symbol {
outer:
	for _, symbol := range s.Table[name] {
		for _, meaning := range meanings {
			if symbol.Flags&meaning == 0 {
				continue outer
			}
		}
		return symbol
	}
	return nil
}

func (s *SymbolTable) GetAll() []*Symbol {
	var result []*Symbol
	for _, symbols := range s.Table {
		result = append(result, symbols...)
	}
	return result
}

func (s *SymbolTable) AppendSymbol(name string, symbol *Symbol) {
	s.Table[name] = append(s.Table[name], symbol)
}

func (s *SymbolTable) Clone() *SymbolTable {
	var result = NewSymbolTable()
	for name, symbols := range s.Table {
		result.Table[name] = symbols
	}
	return result
}